home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Lib / io / io_lib.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  14.3 KB  |  778 lines

  1. /* io.c: This file contains the entire io library */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Lib/io/RCS/io_lib.c,v 6.0 1991/12/18 20:22:26 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Lib/io/RCS/io_lib.c,v 6.0 1991/12/18 20:22:26 jpo Rel $
  9.  *
  10.  * $Log: io_lib.c,v $
  11.  * Revision 6.0  1991/12/18  20:22:26  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "head.h"
  19. #include "q.h"
  20. #include "adr.h"
  21. #include "prm.h"
  22. #include "dr.h"
  23. #include <signal.h>
  24. #include <isode/internet.h>
  25. #include <sys/wait.h>
  26.  
  27.  
  28. extern char     *cmddfldir;
  29. extern char     *submit_addr;
  30. extern int    errno;
  31.  
  32. static  int     mm_cid;       /* process id of child mail process */
  33. static FILE     *io_wfp,
  34.         *io_rfp;
  35.  
  36. extern char    *submit_prog;
  37. int             remote_submit = 0;
  38. char        *submit_port = "4001";
  39. extern  int     protocol_mode;
  40. static enum {
  41.     is_init,
  42.     is_parm,
  43.     is_queue,
  44.     is_addrs,
  45.     is_adend,
  46.     is_txtinit,
  47.     is_data,
  48.     is_txtend,
  49.     } is_state = is_init;
  50.  
  51. #define check_proto(x)    if (is_state != (x)) \
  52.     return io_lose (rp, RP_MECH, "Protocol state mismatch")
  53.  
  54. static int io_init_remote ();
  55. static int io_init_local ();
  56. static int io_lose ();
  57. static void set_protocol_mode ();
  58. static void unset_protocol_mode ();
  59. static int io_rrply ();
  60. static int io_wrec ();
  61. static int io_rrec ();
  62. static int io_tdata_aux ();
  63. static char *io_data_vis ();
  64. SFP    sigpipe;
  65.  
  66. extern void getfpath ();
  67. /* ---------------------  Begin  Routines  -------------------------------- */
  68.  
  69.  
  70.  
  71.  
  72. /*
  73. Initialise for submission
  74. */
  75.  
  76. int io_init (rp)
  77. RP_Buf  *rp;
  78. {
  79.     char *remote_info;
  80.     char _remote_info[BUFSIZ];
  81.  
  82.     is_state = is_init;
  83.     if (io_wfp != NULLFILE) {
  84.         (void) fclose (io_wfp);
  85.         io_wfp = NULLFILE;
  86.     }
  87.     if (io_rfp != NULLFILE) {
  88.         (void) fclose (io_rfp);
  89.         io_rfp = NULLFILE;
  90.     }
  91.  
  92.     if (remote_info = getenv("PP_HOST_INFO"))
  93.     {
  94.         (void) strncpy(_remote_info, remote_info, sizeof _remote_info);
  95.         _remote_info[sizeof _remote_info -1] = '\0';    
  96.         remote_info = _remote_info;
  97.     }
  98.     else if (remote_info = submit_addr)
  99.     {
  100.         (void) strncpy(_remote_info, remote_info, sizeof _remote_info);
  101.         _remote_info[sizeof _remote_info -1] = '\0';
  102.         remote_info = _remote_info;
  103.     }
  104.     else    remote_info = NULLCP;
  105.  
  106.     if (remote_info && *remote_info == '\0')
  107.         remote_info = NULLCP;
  108.  
  109.     PP_TRACE(("remote info %s", remote_info ? remote_info : "<none>"));
  110.  
  111.     if (remote_info) {
  112.         char    *argv[50];
  113.         int    argc, i;
  114.         char    *port_name, *p;
  115.  
  116.         argc = sstr2arg (remote_info, 50, argv, ",");
  117.  
  118.         for (i = 0; i < argc; i++) {
  119.             port_name = submit_port;
  120.  
  121.             if (p = index (argv[i], ':')) {
  122.                 *p++ = '\0';
  123.                 port_name = p;
  124.             }
  125.             if (argv[i][0] == '/') {
  126.                 if (io_init_local (rp, argv[i]) == RP_OK)
  127.                     return RP_OK;
  128.             }
  129.             else {
  130.                 if (io_init_remote (rp, argv[i],
  131.                            port_name) == RP_OK)
  132.                     return RP_OK;
  133.             }
  134.         }
  135.     }
  136.     return (io_init_local (rp, NULLCP));
  137. }
  138.  
  139.  
  140.  
  141.  
  142. /*
  143. Parameter handling
  144. */
  145.  
  146. int io_wprm (prm, rp)
  147. struct prm_vars         *prm;
  148. RP_Buf                  *rp;
  149. {
  150.     int             retval;
  151.  
  152.     PP_DBG (("io_wprm (prm, rp)"));
  153.  
  154.     check_proto (is_init);
  155.  
  156.     if (io_wfp == NULLFILE)
  157.         return (io_lose (rp, RP_MECH, "Not connected to sumbit"));
  158.  
  159.     sigpipe = signal (SIGPIPE, SIG_IGN);
  160.     set_protocol_mode();
  161.     retval = wr_prm (prm, io_wfp);
  162.     (void) fflush (io_wfp);
  163.     unset_protocol_mode();
  164.     (void) signal (SIGPIPE, sigpipe);
  165.  
  166.     if (rp_isbad (retval) || ferror(io_wfp))
  167.         return (io_lose (rp, retval, "Can't write parameters"));
  168.  
  169.     if (rp_isbad (retval = io_rrply (rp)))
  170.         return (io_lose (rp, retval, "Bad handshake"));
  171.  
  172.     is_state = is_parm;
  173.     return (rp -> rp_val);
  174. }
  175.  
  176.  
  177.  
  178.  
  179. /*
  180. Q structure handling
  181. */
  182.  
  183. int io_wrq (qp, rp)
  184. Q_struct        *qp;
  185. RP_Buf          *rp;
  186. {
  187.     int     retval;
  188.  
  189.     PP_DBG (("io_wq (q, rp)"));
  190.  
  191.     if (io_wfp == NULLFILE)
  192.         return (io_lose (rp, RP_MECH, "Not connected to submit"));
  193.     check_proto (is_parm);
  194.  
  195.     sigpipe = signal (SIGPIPE, SIG_IGN);
  196.     set_protocol_mode();
  197.     retval = wr_q (qp, io_wfp);
  198.     (void) fflush (io_wfp);
  199.     unset_protocol_mode();
  200.     (void) signal (SIGPIPE, sigpipe);
  201.  
  202.     if (rp_isbad (retval) || ferror(io_wfp))
  203.         return (io_lose (rp, retval, "Can't write Q structure"));
  204.  
  205.     if (rp_isbad (retval = io_rrply (rp)))
  206.         return (io_lose (rp, retval, "Bad handshake"));
  207.  
  208.     is_state = is_addrs;
  209.     return (rp -> rp_val);
  210. }
  211.  
  212.  
  213.  
  214.  
  215. /*
  216. DR structure handling
  217. */
  218.  
  219. int io_wdr (dp, rp)
  220. DRmpdu          *dp;
  221. RP_Buf          *rp;
  222. {
  223.     int     retval;
  224.  
  225.     PP_DBG (("io_wdr (dp, rp)"));
  226.  
  227.     if (io_wfp == NULLFILE)
  228.         return (io_lose (rp, RP_MECH, "Not connected to submit"));
  229.     check_proto (is_adend);
  230.  
  231.     sigpipe = signal (SIGPIPE, SIG_IGN);
  232.     set_protocol_mode();
  233.     retval = wr_dr (dp, io_wfp);
  234.     (void) fflush (io_wfp);
  235.     unset_protocol_mode();
  236.     (void) signal (SIGPIPE, sigpipe);
  237.  
  238.     if (rp_isbad (retval) || ferror(io_wfp))
  239.         return (io_lose (rp, retval, "Can't write DR structure"));
  240.  
  241.     if (rp_isbad (retval = io_rrply (rp)))
  242.         return (io_lose (rp, retval, "Bad Handshake"));
  243.  
  244.     is_state = is_adend;
  245.     return (rp -> rp_val);
  246. }
  247.  
  248.  
  249.  
  250.  
  251. /*
  252. Address handling
  253. */
  254.  
  255. int io_wadr (ap, type, rp)
  256. ADDR            *ap;
  257. int             type;
  258. RP_Buf          *rp;
  259. {
  260.     int     retval;
  261.  
  262.     PP_DBG (("io_wadr (adr, %d, rp)", type));
  263.  
  264.     if (io_wfp == NULLFILE)
  265.         return (io_lose (rp, RP_MECH, "Not connected to submit"));
  266.     check_proto (is_addrs);
  267.  
  268.     sigpipe = signal (SIGPIPE, SIG_IGN);
  269.     set_protocol_mode();
  270.     retval = wr_adr (ap, io_wfp, type);
  271.     (void) fflush (io_wfp);
  272.     unset_protocol_mode();
  273.     (void) signal (SIGPIPE, sigpipe);
  274.  
  275.     if (rp_isbad (retval) || ferror(io_wfp))
  276.         return (io_lose (rp, retval, "Can't write address"));
  277.  
  278.     if (rp_isbad (retval = io_rrply (rp)))
  279.         return (io_lose (rp, retval, "Bad handshake"));
  280.     if (rp -> rp_val != RP_AOK)
  281.         return RP_BAD;
  282.     return (rp -> rp_val);
  283. }
  284.  
  285.  
  286. /*
  287. Address phase termination
  288. */
  289.  
  290. int io_adend (rp)
  291. RP_Buf          *rp;
  292. {
  293.     int     retval;
  294.  
  295.     PP_DBG (("io_adend (rp)"));
  296.  
  297.     if (io_wfp == NULLFILE)
  298.         return (io_lose (rp, RP_MECH, "Not connected to sumbit"));
  299.     check_proto (is_addrs);
  300.  
  301.     if (rp_isbad (retval = io_wrec ("", 0)))
  302.         return (io_lose (rp, retval, "Problem ending addreses"));
  303.  
  304.     if (rp_isbad (retval = io_rrply (rp)))
  305.         return (io_lose (rp, retval, "Bad Handshake"));
  306.  
  307.     is_state = is_adend;
  308.     return (rp -> rp_val);
  309. }
  310.  
  311.  
  312.  
  313.  
  314. /*
  315. Text phase - initialisation
  316. */
  317.  
  318. int io_tinit (rp)
  319. RP_Buf          *rp;
  320. {
  321.     int     retval;
  322.  
  323.     PP_DBG (("io_tinit()"));
  324.  
  325.     if (io_wfp == NULLFILE)
  326.         return (io_lose (rp, RP_MECH, "Not connected to submit"));
  327.     check_proto (is_adend);
  328.  
  329.     if ( rp_isbad (retval = io_wrec ("", 0)))
  330.         return (io_lose (rp, retval, "Problem in text init"));
  331.  
  332.     if (rp_isbad (retval = io_rrply (rp)))
  333.         return (io_lose (rp, retval, "Bad handshake"));
  334.  
  335.     PP_DBG (("Returned %s\n", rp->rp_line));
  336.     is_state = is_txtinit;
  337.     return (rp -> rp_val);
  338. }
  339.  
  340.  
  341.  
  342.  
  343. /*
  344. Initialise to pass a single body part to submit
  345. */
  346.  
  347. int io_tpart (section, links, rp)
  348. char            *section;
  349. int             links;
  350. RP_Buf          *rp;
  351. {
  352.     int     retval;
  353.  
  354.     PP_DBG (("io_tpart (%s, %d)", section, links));
  355.  
  356.     check_proto (is_txtinit);
  357.     if (rp_isbad (retval = io_wrec (section, strlen (section))))
  358.         return (io_lose (rp, retval, "Error writing to submit"));
  359.  
  360.     if (rp_isbad (retval = io_rrply (rp)))
  361.         return (io_lose (rp, retval, "Handshake failure"));
  362.  
  363.     if (links != TRUE)
  364.         is_state = is_data;
  365.     return (rp -> rp_val);
  366. }
  367.  
  368.  
  369.  
  370.  
  371. /*
  372. Write data to submit.
  373. */
  374.  
  375. int io_tdata (buf, len)
  376. char            *buf;
  377. int             len;
  378. {
  379.     if (is_state != is_data)
  380.         return NOTOK;
  381.     PP_LOG (LLOG_PDUS, ("Lib/io_tdata(%d): %s", len,
  382.                 io_data_vis (buf, len)));
  383.     return (io_tdata_aux (buf, len, TRUE));
  384. }
  385.  
  386.  
  387.  
  388.  
  389. /*
  390. End a section sent to submit
  391. */
  392.  
  393. int io_tdend (rp)
  394. RP_Buf          *rp;
  395. {
  396.     int     retval;
  397.  
  398.     PP_DBG (("io_tdend (ret)"));
  399.  
  400.     check_proto (is_data);
  401.     if (rp_isbad (retval = io_tdata_aux ("", 0, FALSE)))
  402.         return (io_lose (rp, retval, "I/O error"));
  403.  
  404.     (void) fflush (io_wfp);
  405.     if (ferror (io_wfp))
  406.         return (io_lose (rp, RP_FIO, "Write error"));
  407.  
  408.     if (rp_isbad (retval = io_rrply (rp)))
  409.         return (io_lose (rp, retval, "Bad Handshake"));
  410.  
  411.     is_state = is_txtinit;
  412.     return (rp -> rp_val);
  413. }
  414.  
  415.  
  416.  
  417.  
  418. /*
  419. Finally finish the data section
  420. */
  421.  
  422. int io_tend (rp)
  423. RP_Buf          *rp;
  424. {
  425.     int     retval;
  426.  
  427.     PP_DBG (("io_tend (ret)"));
  428.  
  429.     check_proto (is_txtinit);
  430.     if (rp_isbad (retval = io_wrec ("", 0)))
  431.         return (io_lose (rp, retval, "I/O error"));
  432.  
  433.     if (rp_isbad (retval = io_rrply (rp)))
  434.         return (io_lose (rp, retval, "Bad Handshake"));
  435.  
  436.     if (rp_isbad (rp -> rp_val))
  437.         return rp -> rp_val;
  438.  
  439.     if (rp_isbad (retval = io_rrply (rp)))
  440.         return io_lose (rp, retval, "Bad Handshake");
  441.  
  442.     is_state = is_init;
  443.     return (rp -> rp_val);
  444. }
  445.  
  446.  
  447.  
  448.  
  449. int io_end (type)
  450. int     type;
  451. {
  452.     register int   status = OK;
  453.     int pid;
  454. #ifdef SVR4
  455.     int w;
  456. #else
  457.     union wait w;
  458. #endif
  459.  
  460.     PP_DBG (("io_end (%d)", type));
  461.  
  462.     (void) fclose (io_wfp);
  463.     (void) fclose (io_rfp);
  464.     io_rfp = NULLFILE;
  465.     io_wfp = NULLFILE;
  466.  
  467.     if (!remote_submit)
  468. #ifdef SVR4
  469.         while ((pid = wait(&w)) != mm_cid && pid != -1)
  470. #else
  471.         while ((pid = wait(&w.w_status)) != mm_cid && pid != -1)
  472. #endif
  473.             continue;
  474.  
  475.     mm_cid = 0;
  476.     is_state = is_init;
  477.     return (status);
  478. }
  479.  
  480.  
  481.  
  482.  
  483. /* ---------------------  Static  Routines  ------------------------------- */
  484.  
  485.  
  486.  
  487.  
  488. /*
  489. Helper routine if local connection is required
  490. */
  491.  
  492. static int io_init_local (rp, command)
  493. RP_Buf  *rp;
  494. char    *command;
  495. {
  496.     char            temppath[LINESIZE];
  497.     int             sv[2],
  498.             osv[2],
  499.             child,
  500.             i;
  501.  
  502.     PP_DBG (("<pipe> io_init()"));
  503.  
  504.     if (pipe (sv) < 0 || pipe (osv) < 0)
  505.         return (io_lose (rp, RP_LIO,
  506.                 "Can't create connection to child"));
  507.  
  508.     if ((child = tryfork()) < 0) {
  509.         (void) close (sv[0]);
  510.         (void) close (sv[1]);
  511.         (void) close (osv[0]);
  512.         (void) close (osv[1]);
  513.         return (io_lose (rp, RP_LIO, "Try again (fork)"));
  514.     }
  515.  
  516.  
  517.     if (child == 0) {
  518.         /*
  519.         I am the child (I will use sv[1])
  520.         */
  521.  
  522.         if (command && *command)
  523.             (void) strncpy (temppath, command, sizeof temppath);
  524.         else
  525.             getfpath (cmddfldir, submit_prog, temppath);
  526.  
  527.         if (osv[0] != 0) {
  528.             (void) dup2 (osv[0], 0);
  529.             (void) close (osv[0]);
  530.         }
  531.         if (sv[1] != 1) {
  532.             (void) dup2 (sv[1], 1);
  533.             (void) close (sv[1]);
  534.         }
  535.         (void) close (osv[1]);
  536.         (void) close (sv[0]);
  537.         for (i = getdtablesize() ; i >= 2 ; i--)
  538.             (void) close (i);
  539.  
  540.         (void) execl (temppath, submit_prog, 0);
  541.  
  542.         PP_OPER (temppath,  ("Cannot exec"));
  543.  
  544.         _exit (1);
  545.     }
  546.  
  547.     /*
  548.     I am the parent - I will use sv[0]
  549.     */
  550.     mm_cid = child;
  551.     (void) close (sv[1]);
  552.     io_rfp = fdopen (sv[0], "r");
  553.     (void) close (osv[0]);
  554.     io_wfp = fdopen (osv[1], "w");
  555.     return (RP_OK);
  556. }
  557.  
  558.  
  559.  
  560.  
  561. /*
  562. Helper routine for remote connect (submit server)
  563. */
  564.  
  565. static int  io_init_remote (rp, submit_host, submit_port_name)
  566. RP_Buf  *rp;
  567. char    *submit_host;
  568. char    *submit_port_name;
  569. {
  570.     struct servent          *sp;
  571.     u_short                 port;
  572.     struct hostent          *host;
  573.     struct sockaddr_in      s_in;
  574.     int                     sd;
  575.  
  576.     PP_DBG (("<socket> io_init()"));
  577.  
  578.     if (isdigit (*submit_port_name))
  579.         port = htons ((u_short)atoi(submit_port_name));
  580.     else if ((sp = getservbyname (submit_port_name, "tcp")) != NULL)
  581.         port = sp -> s_port;
  582.     else
  583.         port = htons ((u_short)atoi(submit_port));
  584.  
  585.     sd = socket (AF_INET, SOCK_STREAM, 0);
  586.     if (sd < 0)
  587.         return (io_lose (rp, RP_LIO, "Can't get a socket"));
  588.  
  589.     bzero ((char *)&s_in, sizeof (s_in));
  590.     s_in.sin_family = AF_INET;
  591.     s_in.sin_port = port;
  592.  
  593.     if ((host = gethostbyname (submit_host)) == NULL) {
  594.         (void) close (sd);
  595.         PP_LOG (LLOG_EXCEPTIONS,
  596.             ("Remote server %s not found", submit_host));
  597.         return (io_lose (rp, RP_MECH, "Can't locate host"));
  598.     }
  599.  
  600.     bcopy ((char *)host -> h_addr, (char *)&s_in.sin_addr,
  601.            host -> h_length);
  602.  
  603.     if (connect (sd, (struct sockaddr *)&s_in, sizeof s_in) < 0) {
  604.         (void) close (sd);
  605.         return (io_lose (rp, RP_LIO, "Can't connect to submit"));
  606.     }
  607.  
  608.     io_rfp = fdopen (sd, "r");
  609.     io_wfp = fdopen (sd, "w");
  610.  
  611.     if (io_wfp == NULLFILE || io_rfp == NULLFILE)
  612.     {    int was = errno;
  613.         if (io_wfp == NULLFILE)
  614.             (void) fclose(io_wfp);
  615.         if (io_rfp == NULLFILE)
  616.             (void) fclose(io_rfp);
  617.         (void) close(sd);
  618.         errno = was;
  619.         return (io_lose (rp, RP_FIO, "File pointers not set"));
  620.     }
  621.     return (RP_OK);
  622. }
  623.  
  624.  
  625. /*
  626. Helper routine to ensure correct protocol
  627. */
  628.  
  629. static int io_tdata_aux (buf, len, flag)
  630. char            *buf;
  631. int             len;
  632. int             flag;
  633. {
  634.     long    datalen = htonl ((u_long)len);
  635.  
  636.     if (flag && len == 0)
  637.         return (RP_MECH);
  638.  
  639.     (void) fwrite ((char *)&datalen, sizeof (datalen), 1, io_wfp);
  640.     (void) fwrite (buf, sizeof (char), len, io_wfp);
  641.  
  642.     return ((ferror (io_wfp) ? RP_FIO : RP_OK));
  643. }
  644.  
  645.  
  646. /*
  647. Get a reply from remote process
  648. */
  649.  
  650. static int io_rrply (rp)
  651. RP_Buf          *rp;
  652. {
  653.     int     len;
  654.     char    *rplystr;
  655.     int    c;
  656.  
  657.     PP_DBG (("io_rrply (rp)"));
  658.  
  659.     if ((c = getc(io_rfp)) == EOF)
  660.         return RP_EOF;
  661.     rp -> rp_val = c;
  662.     for (rplystr = rp -> rp_line, len = sizeof rp -> rp_line - 2;
  663.          len > 0; len --) {
  664.         if ((c = getc(io_rfp)) == EOF)
  665.             return RP_EOF;
  666.         if (c == '\n')
  667.             break;
  668.         *rplystr++ = c;
  669.     }
  670.     if (c != '\n') {    /* no newline - find it */
  671.         while ((c = getc(io_rfp)) != EOF && c != '\n')
  672.             continue;
  673.     }
  674.     *rplystr = '\0';
  675.  
  676.     rplystr = rp_valstr ((int)rp -> rp_val);
  677.  
  678.     if (*rplystr == '*') {
  679.         /*
  680.         Replyer did a no-no
  681.         */
  682.         PP_LOG (LLOG_EXCEPTIONS, ("ILLEGAL REPLY: (%s)", rplystr));
  683.         rp -> rp_val = RP_RPLY;
  684.     }
  685.  
  686.     return (RP_OK);
  687. }
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694. /*
  695. Write a record
  696. */
  697.  
  698. static int io_wrec (linebuf, len)   /* write a record/packet */
  699. register char   *linebuf;       /* chars to write */
  700. register int    len;            /* number of chars to write */
  701. {
  702.     static char *io_data_vis ();
  703.     PP_LOG (LLOG_PDUS, ("io_wrec ('%s', %d)",
  704.                 io_data_vis (linebuf, len), len));
  705.  
  706.  
  707.     sigpipe = signal (SIGPIPE, SIG_IGN);
  708.     (void) fwrite (linebuf, sizeof (char), len, io_wfp);
  709.     (void) putc ('\n', io_wfp);
  710.     (void) fflush (io_wfp);   /* force it out */
  711.     (void) signal (SIGPIPE, sigpipe);
  712.  
  713.     return (ferror (io_wfp) ? RP_LIO : RP_OK);
  714. }
  715.  
  716.  
  717.  
  718.  
  719. static int io_lose (rp, state, str)
  720. RP_Buf          *rp;
  721. int             state;
  722. char            *str;
  723. {
  724.     rp -> rp_val = rp_gval (state);
  725.  
  726.     (void) strcpy (rp -> rp_line, str);
  727.  
  728.     PP_LOG (LLOG_NOTICE,
  729.         ("io_lose -> %s [%s]", rp_valstr (state), str));
  730.  
  731.     is_state = is_init;
  732.     return (state);
  733. }
  734.  
  735. static  char *io_data_vis (str, n)
  736. char    *str;
  737. int     n;
  738. {
  739.     static char    buffer[128];
  740.     char *cp, *ep;
  741.  
  742.     for(cp = buffer, ep = buffer + sizeof(buffer) -1;
  743.         cp < ep && n-- > 0; str ++) {
  744.         if (isprint (*str))
  745.             *cp++ = *str;
  746.         else if (cp >= ep - 3)
  747.             break;
  748.         else {
  749.             *cp ++ = '\\';
  750.             *cp ++ = '0' + ((*str >> 6) & 03);
  751.             *cp ++ = '0' + ((*str >> 3) & 07);
  752.             *cp ++ = '0' + ((*str) & 07);
  753.         }
  754.     }
  755.     *cp = 0;
  756.     return buffer;
  757. }
  758.  
  759. static void set_protocol_mode ()
  760. {
  761.     unset_protocol_mode();
  762.     protocol_mode = 1;
  763.     return;
  764. }
  765.  
  766.  
  767. static void unset_protocol_mode ()
  768. {
  769.     static int      save = -1;
  770.  
  771.     if (save == -1)
  772.         save = protocol_mode;
  773.     else {
  774.         protocol_mode = save;
  775.         save = -1;
  776.     }
  777. }
  778.